//
//  TFRequest.m
//  TFFoundation
//
//  Created by TFAppleWork-Summer on 2017/3/20.
//  Copyright © 2017年 TFAppleWork-Summer. All rights reserved.
//

#import "TFRequest.h"
#import <AFNetworking/AFNetworking.h>
#import "TFGzipRequestSerializer.h"
#import "TFGzipResponseSerializer.h"
#import "TFRequesHelper.h"

NSString * const kTFRequestCacheSaveKey = @"TFRequestCacheSave";

NSString * const kTFRequestAuthorizationHeaderUsernameKey = @"TFRequestAuthorizationHeaderUsername";

NSString * const kTFRequestAuthorizationHeaderPasswordKey = @"TFRequestAuthorizationHeaderPassword";

@interface TFRequest ()

@property (nonatomic, strong, readwrite) id responseObject;

@property (nonatomic, assign, readwrite) BOOL responseObjectIsCache;

@property (nonatomic, assign, readwrite) NSTimeInterval costTime;

@property (nonatomic, strong, readwrite) NSURLSessionTask *sessionTask;

@property (nonatomic, assign, readwrite) TFRequestState requestState;


@end

@implementation TFRequest

- (instancetype)init {
    self = [super init];
    if (self) {
        self.requestSerializerType = TFRequestSerializerTypeHTTP;
        self.responseSerializerType = TFResponseSerializerTypeJSON;
        self.requestMethod = TFRequestMethodPost;
        self.timeoutInterval = 10.0f;
        self.requestState = TFRequestStateNone;
    }
    return self;
}

+ (void)checkNetworkStatusUsingBlock:(TFRequestCheckNetStatusBlock)block {
    if (block) {
        AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager];
        [manager startMonitoring];
        [manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
            if (block) {
                block(status);
            }
        }];
    }
}

+ (void)stopCheckNetworkStatus {
    [[AFNetworkReachabilityManager sharedManager] stopMonitoring];
}

- (id)cachedResponseObject {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    return [[userDefaults objectForKey:kTFRequestCacheSaveKey] objectForKey:[self p_getCacheKey]];
}

- (BOOL)cacheResponseObject {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    NSMutableDictionary *cacheDic = [NSMutableDictionary dictionaryWithDictionary:[userDefaults objectForKey:kTFRequestCacheSaveKey]?:[NSDictionary dictionary]];
    [cacheDic setObject:self.responseObject forKey:[self p_getCacheKey]];
    [userDefaults setObject:cacheDic forKey:kTFRequestCacheSaveKey];
    return [userDefaults synchronize];
}

- (void)convertCacheToResponse {
    _responseObject = self.cachedResponseObject;
    _responseObjectIsCache = YES;
    _error = nil;
    [self mapResponseJsonObject];
    if (_responseMapObject) {
        _responseObject = _responseMapObject;
    }
}

- (BOOL)clearCache {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    NSMutableDictionary *cacheDic = [NSMutableDictionary dictionaryWithDictionary:[userDefaults objectForKey:kTFRequestCacheSaveKey]?:[NSDictionary dictionary]];
    [cacheDic removeObjectForKey:[self p_getCacheKey]];
    [userDefaults setObject:cacheDic forKey:kTFRequestCacheSaveKey];
    return [userDefaults synchronize];
}

+ (BOOL)clearAllCache {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults removeObjectForKey:kTFRequestCacheSaveKey];
    return [userDefaults synchronize];
}

- (NSString *)p_getCacheKey {
    NSString *cacheKey = [NSString stringWithFormat:@"baseUrl:%@ path:%@ params:%@",self.baseURL,self.path,self.params];
    return [TFRequesHelper tf_request_md5StringWithSrting:cacheKey];
}

- (void)startRequestWithResponseBlock:(TFRequestResponseBlock)responseBlock {
    [self startRequestWithProgressBlock:nil responseBlock:responseBlock];
}

- (void)startRequestWithProgressBlock:(TFRequestProgressBlock)progressBlock responseBlock:(TFRequestResponseBlock)responseBlock {
    [self startRequestWithConstructingBodyBlock:nil progressBlock:progressBlock responseBlock:responseBlock];
}

- (void)startRequestWithConstructingBodyBlock:(TFConstructingBodyBlock)constructingBodyBlock progressBlock:(nullable TFRequestProgressBlock)progressBlock responseBlock:(nullable TFRequestResponseBlock)responseBlock {
    _requestState = TFRequestStateLoading;
    if (!constructingBodyBlock) {
        constructingBodyBlock = _construtingBodyBlock;
    }
    if (!progressBlock) {
        progressBlock = _progressBlock;
    }
    if (!responseBlock) {
        responseBlock = _responseBlock;
    }
    
    AFHTTPSessionManager *sessionManager = nil;
    if (self.customSesstionManagerClass) {
        sessionManager = [[self.customSesstionManagerClass alloc] initWithBaseURL:[NSURL URLWithString:self.baseURL]];
    }
    else {
        sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:self.baseURL]];
    }
    
    switch (_requestSerializerType) {
        case TFRequestSerializerTypeHTTP:
            sessionManager.requestSerializer = [AFHTTPRequestSerializer serializer];
            break;
        case TFRequestSerializerTypeJSON:
            sessionManager.requestSerializer = [AFJSONRequestSerializer serializer];
            break;
        case TFRequestSerializerTypeGZIP:
            sessionManager.requestSerializer = [TFGzipRequestSerializer serializer];
            break;
        case TFRequestSerializerTypePropertyList:
            sessionManager.requestSerializer = [AFPropertyListRequestSerializer serializer];
            break;
        case TFRequestSerializerTypeCustom:
            sessionManager.requestSerializer = self.customRequestSerializer;
        default:
            break;
    }
    _sessionManager = sessionManager;
    if (self.requestAuthorizationHeeader.count) {
        [sessionManager.requestSerializer setAuthorizationHeaderFieldWithUsername:self.requestAuthorizationHeeader[kTFRequestAuthorizationHeaderUsernameKey] password:self.requestAuthorizationHeeader[kTFRequestAuthorizationHeaderPasswordKey]];
    }
    //设置超时时间
    sessionManager.requestSerializer.timeoutInterval = self.timeoutInterval;
    
    switch (_responseSerializerType) {
        case TFResponseSerializerTypeHTTP:
            sessionManager.responseSerializer = [AFHTTPResponseSerializer serializer];
            break;
        case TFResponseSerializerTypeJSON:
            sessionManager.responseSerializer = [AFJSONResponseSerializer serializer];
            break;
        case TFResponseSerializerTypeGZIP:
            sessionManager.responseSerializer = [TFGzipResponseSerializer serializer];
            break;
        case TFResponseSerializerTypePropertyList:
            sessionManager.responseSerializer = [AFPropertyListResponseSerializer serializer];
            break;
        case TFResponseSerializerTypeCustom:
            sessionManager.responseSerializer = self.customResponseSerializer;
        default:
            break;
    }
    if (_requestMethod==TFRequestMethodDownload) {
        sessionManager.requestSerializer = [AFHTTPRequestSerializer serializer];
        sessionManager.responseSerializer = [AFHTTPResponseSerializer serializer];
    }
    if (_acceptableContentTypesSet) {
        sessionManager.responseSerializer.acceptableContentTypes = _acceptableContentTypesSet;
    }
    NSDate *startDate = nil;
    startDate = [NSDate date];
    void(^sessionConstructingBodyBlock)(id <AFMultipartFormData> formData) = nil;
    if (constructingBodyBlock) {
        sessionConstructingBodyBlock = ^(id<AFMultipartFormData> formData) {
            if (constructingBodyBlock) {
                constructingBodyBlock(formData);
            }
        };
    }
    void(^sessionProgressBlock)(NSProgress *downloadProgress) = nil;
    if (progressBlock) {
        sessionProgressBlock = ^(NSProgress *downloadProgress) {
            if (progressBlock) {
                progressBlock(downloadProgress.fractionCompleted);
            }
        };
    }
    if (_sessionManagerConfigBlock) {
        _sessionManagerConfigBlock(self,sessionManager);
    }
    
    //发起请求
    _sessionTask = [self p_startRequestWithSessionManager:sessionManager constructingBodyBlock:sessionConstructingBodyBlock progressBlock:sessionProgressBlock successBlock:^(NSURLSessionTask *task, id  _Nullable responseObject) {
        [sessionManager.session finishTasksAndInvalidate];
        _responseObject = responseObject;
        _error = nil;
        [self mapResponseJsonObject];
        [self p_handleResponseWithResponseBlock:responseBlock startDate:startDate];
    } failureBlock:^(NSURLSessionTask * _Nullable task, NSError *error) {
        [sessionManager.session finishTasksAndInvalidate];
        _error = error;
        _responseObject = nil;
        [self p_handleResponseWithResponseBlock:responseBlock startDate:startDate];
    }];
}

- (void)resetResponseObjectWithResponse:(id)response {
    _responseObject = response;
}

- (NSURLSessionTask *)p_startRequestWithSessionManager:(AFHTTPSessionManager *)sessionManager
                             constructingBodyBlock:(void (^)(id <AFMultipartFormData> formData))constructingBodyBlock
                                              progressBlock:(void (^)(NSProgress *downloadProgress))progressBlock
                                               successBlock:(void (^)(NSURLSessionTask *task, id responseObject))successBlock
                                               failureBlock:(void (^)(NSURLSessionTask *task, NSError *error))failureBlock
{
    //根据请求方法发送请求
    switch (_requestMethod) {
        case TFRequestMethodGet:
        {
            return [sessionManager GET:self.path parameters:self.params headers:self.extraRequestHeaders progress:progressBlock success:successBlock failure:failureBlock];
        }
            break;
        case TFRequestMethodPost:
        {
            if (constructingBodyBlock) {
                return [sessionManager POST:self.path parameters:self.params headers:self.extraRequestHeaders  constructingBodyWithBlock:constructingBodyBlock progress:progressBlock success:successBlock failure:failureBlock];
            }
            else {
                return [sessionManager POST:self.path parameters:self.params headers:self.extraRequestHeaders  progress:progressBlock success:successBlock failure:failureBlock];
            }
        }
            break;
        case TFRequestMethodPut:{
            return [sessionManager PUT:self.path parameters:self.params headers:self.extraRequestHeaders  success:successBlock failure:failureBlock];
        }
            break;
        case TFRequestMethodHead: {
            return [sessionManager HEAD:self.path parameters:self.params headers:self.extraRequestHeaders  success:^(NSURLSessionDataTask * _Nonnull task) {
                if (successBlock) {
                    successBlock(task,nil);
                }
            } failure:failureBlock];
        }
            break;
        case TFRequestMethodPatch: {
            return [sessionManager PATCH:self.path parameters:self.params headers:self.extraRequestHeaders  success:successBlock failure:failureBlock];
        }
            break;
        case TFRequestMethodDelete: {
            return [sessionManager DELETE:self.path parameters:self.params headers:self.extraRequestHeaders success:successBlock failure:failureBlock];
        }
            break;
        case TFRequestMethodDownload: {
            NSString *downloadUrl = [self.baseURL stringByAppendingString:self.path];
            NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:downloadUrl]];
            NSURLSessionTask *task = [sessionManager downloadTaskWithRequest:request progress:progressBlock destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
                NSString *path = [self.downloadLocalPath stringByAppendingPathComponent:response.suggestedFilename];
                return [NSURL fileURLWithPath:path];
            } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
                if (error) {
                    if (failureBlock) {
                        failureBlock(task,error);
                    }
                }
                else {
                    if (successBlock) {
                        successBlock(task,filePath);
                    }
                }
            }];
            return task;
        }
            break;
        default:
            break;
    }
}

- (void)p_handleResponseWithResponseBlock:(TFRequestResponseBlock)responseBlock startDate:(NSDate *)startDate {
    NSDate *endDate = [NSDate date];
    _costTime = [endDate timeIntervalSinceDate:startDate];
    _responseObjectIsCache = NO;
    
    if (self.error) {
        _requestState = TFRequestStateError;
    }
    else {
        _requestState = TFRequestStateSuccess;
        if (_responseObject&&_isCache) {
            BOOL cache = [self cacheResponseObject];
        }
    }
    if (responseBlock) {
        responseBlock(self,_responseMapObject?:_responseObject,_error);
    }
}

- (void)mapResponseJsonObject {
    
}

@end
